Get scrollbars out of the way of the window's resize grip
authorMatthias Clasen <mclasen@redhat.com>
Fri, 8 Oct 2010 05:37:33 +0000 (01:37 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 8 Oct 2010 06:14:19 +0000 (02:14 -0400)
If there are both horizontal and vertical scrollbars, there is
an unused 'corner' into which the resize grip fits. Individual
scrollbars need to be shortened and moved to make room for the
resize grip.

gtk/gtkrange.c

index fd9ae0e1757406501cd21e13b7845c6e9ea640b9..ab363419f63126c9a3db6d84d65873ae39f7dde9 100644 (file)
@@ -37,6 +37,7 @@
 #include "gtkrange.h"
 #include "gtkscale.h"
 #include "gtkscrollbar.h"
+#include "gtkwindow.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 
@@ -185,6 +186,8 @@ static void gtk_range_size_request   (GtkWidget        *widget,
                                       GtkRequisition   *requisition);
 static void gtk_range_size_allocate  (GtkWidget        *widget,
                                       GtkAllocation    *allocation);
+static void gtk_range_hierarchy_changed (GtkWidget     *widget,
+                                         GtkWidget     *previous_toplevel);
 static void gtk_range_realize        (GtkWidget        *widget);
 static void gtk_range_unrealize      (GtkWidget        *widget);
 static void gtk_range_map            (GtkWidget        *widget);
@@ -215,6 +218,8 @@ static void update_slider_position   (GtkRange             *range,
                                      gint              mouse_x,
                                      gint              mouse_y);
 static void stop_scrolling           (GtkRange         *range);
+static gboolean modify_allocation_for_window_grip (GtkWidget     *widget,
+                                                   GtkAllocation *allocation);
 
 /* Range methods */
 
@@ -290,8 +295,9 @@ gtk_range_class_init (GtkRangeClass *class)
   widget_class->destroy = gtk_range_destroy;
   widget_class->size_request = gtk_range_size_request;
   widget_class->size_allocate = gtk_range_size_allocate;
+  widget_class->hierarchy_changed = gtk_range_hierarchy_changed;
   widget_class->realize = gtk_range_realize;
-  widget_class->unrealize = gtk_range_unrealize;  
+  widget_class->unrealize = gtk_range_unrealize;
   widget_class->map = gtk_range_map;
   widget_class->unmap = gtk_range_unmap;
   widget_class->draw = gtk_range_draw;
@@ -1560,7 +1566,7 @@ gtk_range_size_request (GtkWidget      *widget,
                        &stepper_spacing, NULL,
                        NULL, NULL);
 
-  gtk_range_calc_request (range, 
+  gtk_range_calc_request (range,
                           slider_width, stepper_size,
                           focus_width, trough_border, stepper_spacing,
                           &range_rect, &border, NULL, NULL, NULL, NULL);
@@ -1569,6 +1575,65 @@ gtk_range_size_request (GtkWidget      *widget,
   requisition->height = range_rect.height + border.top + border.bottom;
 }
 
+static gboolean
+modify_allocation_for_window_grip (GtkWidget     *widget,
+                                   GtkAllocation *allocation)
+{
+  GtkRange *range = GTK_RANGE (widget);
+  GtkRangePrivate *priv = range->priv;
+  GtkWidget *window;
+  GdkRectangle grip_rect;
+  GdkRectangle translated_rect;
+  gint x;
+  gint y;
+
+  window = gtk_widget_get_toplevel (widget);
+  if (!GTK_IS_WINDOW (window))
+    return FALSE;
+
+  if (!gtk_window_resize_grip_is_visible (GTK_WINDOW (window)))
+    return FALSE;
+
+  /* Get the area of the window's corner grip */
+  gtk_window_get_resize_grip_area (GTK_WINDOW (window), &grip_rect);
+
+  x = 0;
+  y = 0;
+
+  /* Translate the stepper's area into window coords */
+  if (gtk_widget_translate_coordinates (gtk_widget_get_parent (widget),
+                                        window,
+                                        allocation->x,
+                                        allocation->y,
+                                        &x,
+                                        &y))
+    {
+      translated_rect.x = x;
+      translated_rect.y = y;
+      translated_rect.width = allocation->width;
+      translated_rect.height = allocation->height;
+
+      /* If the stepper button intersects the window resize grip.. */
+      if (gdk_rectangle_intersect (&grip_rect, &translated_rect, NULL))
+        {
+          if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+            {
+              allocation->width -= grip_rect.width;
+              if (gtk_widget_get_direction (window) == GTK_TEXT_DIR_RTL)
+                allocation->x += grip_rect.width;
+            }
+          else
+            {
+              allocation->height -= grip_rect.height;
+            }
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 static void
 gtk_range_size_allocate (GtkWidget     *widget,
                          GtkAllocation *allocation)
@@ -1576,6 +1641,7 @@ gtk_range_size_allocate (GtkWidget     *widget,
   GtkRange *range = GTK_RANGE (widget);
   GtkRangePrivate *priv = range->priv;
 
+  modify_allocation_for_window_grip (widget, allocation);
   gtk_widget_set_allocation (widget, allocation);
 
   priv->recalc_marks = TRUE;
@@ -1589,6 +1655,30 @@ gtk_range_size_allocate (GtkWidget     *widget,
                             allocation->width, allocation->height);
 }
 
+static void
+resize_grip_visible_changed (GObject    *object,
+                             GParamSpec *pspec,
+                             gpointer    user_data)
+{
+  gtk_widget_queue_resize (GTK_WIDGET (user_data));
+}
+
+static void
+gtk_range_hierarchy_changed (GtkWidget *widget,
+                             GtkWidget *previous_toplevel)
+{
+  GtkWidget *window;
+
+  if (previous_toplevel)
+    g_signal_handlers_disconnect_by_func (previous_toplevel,
+                                          G_CALLBACK (resize_grip_visible_changed),
+                                          widget);
+  window = gtk_widget_get_toplevel (widget);
+  if (GTK_IS_WINDOW (window))
+    g_signal_connect (window, "notify::resize-grip-visible",
+                      G_CALLBACK (resize_grip_visible_changed), widget);
+}
+
 static void
 gtk_range_realize (GtkWidget *widget)
 {
@@ -1597,10 +1687,10 @@ gtk_range_realize (GtkWidget *widget)
   GtkRangePrivate *priv = range->priv;
   GdkWindow *window;
   GdkWindowAttr attributes;
-  gint attributes_mask;  
+  gint attributes_mask;
 
   gtk_range_calc_layout (range, priv->adjustment->value);
-  
+
   gtk_widget_set_realized (widget, TRUE);
 
   window = gtk_widget_get_parent_window (widget);
@@ -1608,6 +1698,8 @@ gtk_range_realize (GtkWidget *widget)
   g_object_ref (window);
 
   gtk_widget_get_allocation (widget, &allocation);
+  if (modify_allocation_for_window_grip (widget, &allocation))
+    gtk_widget_set_allocation (widget, &allocation);
 
   attributes.window_type = GDK_WINDOW_CHILD;
   attributes.x = allocation.x;